module OH_SOH_LOOP(
   GLB_RESET,
  // receive data bus
   RCLK_155M,
   FRM2OH_FAS_FAIL,
   FRM2OH_FCNT8,
   FRM2OH_FCNT270,
   FRM2OH_FCNT9,
   FRM2OH_DATA,
  // transmit data bus from loop control
   TX_CLK155M,
   TX_SOH_LOOP_EN,
   TX_DBIN_TDATA,
   TX_DBIN_FCNT8,
   TX_DBIN_FCNT270,
   TX_DBIN_FCNT9,
   TX_DBIN_MFCNT64,
  // transmit data bus to SOH insert
   TX_DBOUT_TDATA,
   TX_DBOUT_FCNT8,
   TX_DBOUT_FCNT270,
   TX_DBOUT_FCNT9,
   TX_DBOUT_MFCNT64,
   TX_DBOUT_RX_LOOP_SOH
   );

input                 GLB_RESET;
input                 RCLK_155M;

input                 FRM2OH_FAS_FAIL;
input[2:0]            FRM2OH_FCNT8;
input[8:0]            FRM2OH_FCNT270;
input[3:0]            FRM2OH_FCNT9;
input[63:0]           FRM2OH_DATA;

input                 TX_CLK155M;
input                 TX_SOH_LOOP_EN;
input[63:0]           TX_DBIN_TDATA;
input[2:0]            TX_DBIN_FCNT8;
input[8:0]            TX_DBIN_FCNT270;
input[3:0]            TX_DBIN_FCNT9;
input[5:0]            TX_DBIN_MFCNT64;

output reg[63:0]      TX_DBOUT_TDATA;
output reg[2:0]       TX_DBOUT_FCNT8;
output reg[8:0]       TX_DBOUT_FCNT270;
output reg[3:0]       TX_DBOUT_FCNT9;
output reg[5:0]       TX_DBOUT_MFCNT64;
output reg[63:0]      TX_DBOUT_RX_LOOP_SOH;

//****
//Module function description
// frame overhead buffer byte map 
//   0x00---J0         0x01---E1          0x02---F1        0x03---D1
//   0x04---D2         0x05---D3          0x06---K1        0x07---K2
//   0x08---D4         0x09---D5          0x0A---D6        0x0B---D7
//   0x0C---D8         0x0D---D9          0x0E---D10       0x0F---D11
//   0x10---D12        0x11---S1          0x12---M0/M1     0x13---E2
//   others-XX

reg                  ROH_WR_OHEN;
reg[15:0]            ROH_WR_DATA;
reg                  ROH_WR_FRAME_END;
reg[4:0]             ROH_WR_PAGE, ROH_WR_ADDR;
reg                  ROH_PAGE_RENEW;
reg[4:0]             ROH_RESERVE_FOR_WR_PAGE;


wire[9:0]             ROH_RAM_ADDRA, ROH_RAM_ADDRB;
wire                  ROH_RAM_CLKA, ROH_RAM_CLKB;
wire                  ROH_RAM_WEA;
wire[17:0]            ROH_RAM_DIA, ROH_RAM_DOB;


reg                  TOH_PAGE_RENEW_ME1, TOH_PAGE_RENEW_ME2, TOH_PAGE_RENEW_ME3;
reg[4:0]             TOH_RESERVE_FOR_WR_PAGE;

reg                  TOH_RD_OHEN;
reg                  TOH_RD_FRAME_END;
reg[4:0]             TOH_RD_PAGE, TOH_RD_ADDR;
reg                  TOH_RD_OHEN_ME2,TOH_RD_OHEN_ME3;             // delay overhead byte flag wait for RAM read

reg[63:0]            TX_TDATA_ME1, TX_TDATA_ME2, TX_TDATA_ME3;
reg[2:0]             TX_FCNT8_ME1, TX_FCNT8_ME2, TX_FCNT8_ME3;
reg[8:0]             TX_FCNT270_ME1, TX_FCNT270_ME2, TX_FCNT270_ME3;
reg[3:0]             TX_FCNT9_ME1, TX_FCNT9_ME2, TX_FCNT9_ME3;
reg[5:0]             TX_MFCNT64_ME1, TX_MFCNT64_ME2, TX_MFCNT64_ME3;



//**** Section 0: Buffer Write address generate and trigger address transfer   ****//
always @( posedge GLB_RESET or posedge RCLK_155M ) begin
   if ( GLB_RESET==1'b1 )
      ROH_WR_OHEN                       <= 1'b0;
   else begin
      ROH_WR_OHEN                       <= ((FRM2OH_FCNT9[3:0]==4'd0 && FRM2OH_FCNT270[8:0]==9'd6 && FRM2OH_FCNT8[2:0]==3'b000)) |     // J0 byte enable
                                           ((FRM2OH_FCNT9[3:0]==4'd1 && FRM2OH_FCNT270[8:0]==9'd3 && FRM2OH_FCNT8[2:0]==3'b000)) |     // E1 byte enable
                                           ((FRM2OH_FCNT9[3:0]==4'd1 && FRM2OH_FCNT270[8:0]==9'd6 && FRM2OH_FCNT8[2:0]==3'b000)) |     // F1 byte enable
                                           ((FRM2OH_FCNT9[3:0]==4'd2 && FRM2OH_FCNT270[8:0]==9'd0 && FRM2OH_FCNT8[2:0]==3'b000)) |     // D1 byte enable
                                           ((FRM2OH_FCNT9[3:0]==4'd2 && FRM2OH_FCNT270[8:0]==9'd3 && FRM2OH_FCNT8[2:0]==3'b000)) |     // D2 byte enable
                                           ((FRM2OH_FCNT9[3:0]==4'd2 && FRM2OH_FCNT270[8:0]==9'd6 && FRM2OH_FCNT8[2:0]==3'b000)) |     // D3 byte enable
                                           ((FRM2OH_FCNT9[3:0]==4'd4 && FRM2OH_FCNT270[8:0]==9'd3 && FRM2OH_FCNT8[2:0]==3'b000)) |     // K1 byte enable
                                           ((FRM2OH_FCNT9[3:0]==4'd4 && FRM2OH_FCNT270[8:0]==9'd6 && FRM2OH_FCNT8[2:0]==3'b000)) |     // K2 byte enable
                                           ((FRM2OH_FCNT9[3:0]==4'd5 && FRM2OH_FCNT270[8:0]==9'd0 && FRM2OH_FCNT8[2:0]==3'b000)) |     // D4 byte enable;
                                           ((FRM2OH_FCNT9[3:0]==4'd5 && FRM2OH_FCNT270[8:0]==9'd3 && FRM2OH_FCNT8[2:0]==3'b000)) |     // D5 byte enable;
                                           ((FRM2OH_FCNT9[3:0]==4'd5 && FRM2OH_FCNT270[8:0]==9'd6 && FRM2OH_FCNT8[2:0]==3'b000)) |     // D6 byte enable;
                                           ((FRM2OH_FCNT9[3:0]==4'd6 && FRM2OH_FCNT270[8:0]==9'd0 && FRM2OH_FCNT8[2:0]==3'b000)) |     // D7 byte enable;
                                           ((FRM2OH_FCNT9[3:0]==4'd6 && FRM2OH_FCNT270[8:0]==9'd3 && FRM2OH_FCNT8[2:0]==3'b000)) |     // D8 byte enable;
                                           ((FRM2OH_FCNT9[3:0]==4'd6 && FRM2OH_FCNT270[8:0]==9'd6 && FRM2OH_FCNT8[2:0]==3'b000)) |     // D9 byte enable;
                                           ((FRM2OH_FCNT9[3:0]==4'd7 && FRM2OH_FCNT270[8:0]==9'd0 && FRM2OH_FCNT8[2:0]==3'b000)) |     // D10 byte enable;
                                           ((FRM2OH_FCNT9[3:0]==4'd7 && FRM2OH_FCNT270[8:0]==9'd3 && FRM2OH_FCNT8[2:0]==3'b000)) |     // D11 byte enable;
                                           ((FRM2OH_FCNT9[3:0]==4'd7 && FRM2OH_FCNT270[8:0]==9'd6 && FRM2OH_FCNT8[2:0]==3'b000)) |     // D12 byte enable;
                                           ((FRM2OH_FCNT9[3:0]==4'd8 && FRM2OH_FCNT270[8:0]==9'd0 && FRM2OH_FCNT8[2:0]==3'b000)) |     // S1 byte enable;
                                           ((FRM2OH_FCNT9[3:0]==4'd8 && FRM2OH_FCNT270[8:0]==9'd3 && FRM2OH_FCNT8[2:0]==3'b000)) |     // M1,M0 byte enable;
                                           ((FRM2OH_FCNT9[3:0]==4'd8 && FRM2OH_FCNT270[8:0]==9'd6 && FRM2OH_FCNT8[2:0]==3'b000));     // E2 byte enable;
   end
end
always @( posedge GLB_RESET or posedge RCLK_155M ) begin
   if ( GLB_RESET==1'b1 )
      ROH_WR_DATA[15:0]                 <= 16'd0;
   else begin
      if ( FRM2OH_FCNT9[3:0]==4'd8 && FRM2OH_FCNT270[8:0]==9'd3 && FRM2OH_FCNT8[2:0]==3'b000 )
         ROH_WR_DATA[15:0]              <= FRM2OH_DATA[55:40];
      else
         ROH_WR_DATA[15:0]              <= {1'b0, FRM2OH_DATA[63:56]};
   end
end

always @( posedge GLB_RESET or posedge RCLK_155M ) begin
   if ( GLB_RESET==1'b1 )
      ROH_WR_FRAME_END                  <= 1'b0;
   else
      ROH_WR_FRAME_END                  <= (FRM2OH_FCNT9[3:0]==4'd8 && FRM2OH_FCNT270[8:0]==9'd269 && FRM2OH_FCNT8[2:0]==3'b111);
end


always @( posedge GLB_RESET or posedge RCLK_155M ) begin
   if ( GLB_RESET==1'b1 )
      ROH_WR_PAGE[4:0]                  <= 5'd0;
   else begin
      if ( ROH_WR_FRAME_END==1'b1 )
         ROH_WR_PAGE[4:0]               <= ROH_WR_PAGE[4:0] +5'd1;
   end
end
always @( posedge GLB_RESET or posedge RCLK_155M ) begin
   if ( GLB_RESET==1'b1 )
      ROH_WR_ADDR[4:0]                  <= 5'd0;
   else begin
      if ( ROH_WR_FRAME_END==1'b1 )
         ROH_WR_ADDR[4:0]               <= 5'd0;
      else if ( ROH_WR_OHEN==1'b1 )
         ROH_WR_ADDR[4:0]               <= ROH_WR_ADDR[4:0] +5'd1;
   end
end


/**** RAM instance and page number timing domain change ****/
  assign ROH_RAM_ADDRA[9:0]  = { ROH_WR_PAGE[4:0], ROH_WR_ADDR[4:0] };
  assign ROH_RAM_CLKA        = RCLK_155M;
  assign ROH_RAM_WEA         = ROH_WR_OHEN;
  assign ROH_RAM_DIA[17:0]   = { 2'b00, ROH_WR_DATA[15:0] };

  assign ROH_RAM_ADDRB[9:0]  = { TOH_RD_PAGE[4:0], TOH_RD_ADDR[4:0] };
  assign ROH_RAM_CLKB        = TX_CLK155M;

always @( posedge GLB_RESET or posedge RCLK_155M ) begin
   if ( GLB_RESET==1'b1 )
      ROH_PAGE_RENEW                 <= 1'b0;
   else
      ROH_PAGE_RENEW                 <= ( FRM2OH_FCNT9[3:0]==4'd0 && FRM2OH_FCNT270[8:0]==9'd0 );
end
always @( posedge GLB_RESET or posedge RCLK_155M ) begin
   if ( GLB_RESET==1'b1 )
      ROH_RESERVE_FOR_WR_PAGE[4:0]            <= 5'd0;
   else begin
      if ( FRM2OH_FCNT9[3:0]==4'd8 && FRM2OH_FCNT270[8:0]==9'd269 && FRM2OH_FCNT8[2:0]==3'b111 )
         ROH_RESERVE_FOR_WR_PAGE[4:0]         <= ROH_WR_PAGE[4:0] +5'd1;
   end
end




OH_SOH_LOOP_OHRAM_WRAP                 INST_ROH_RAM(
    .CLKA                              ( ROH_RAM_CLKA ),
    .WEA                               ( ROH_RAM_WEA ),
    .ADDRA                             ( ROH_RAM_ADDRA[9:0] ),
    .DINA                              ( ROH_RAM_DIA[17:0] ),
    .CLKB                              ( ROH_RAM_CLKB ),
    .ADDRB                             ( ROH_RAM_ADDRB[9:0] ),
    .DOUTB                             ( ROH_RAM_DOB[17:0] )
   );


always @( posedge GLB_RESET or posedge TX_CLK155M ) begin
   if ( GLB_RESET==1'b1 ) begin
      TOH_PAGE_RENEW_ME1               <= 1'b0;
      TOH_PAGE_RENEW_ME2               <= 1'b0;
      TOH_PAGE_RENEW_ME3               <= 1'b0;
   end
   else begin
      TOH_PAGE_RENEW_ME1               <= ROH_PAGE_RENEW;
      TOH_PAGE_RENEW_ME2               <= TOH_PAGE_RENEW_ME1;
      TOH_PAGE_RENEW_ME3               <= TOH_PAGE_RENEW_ME2;
   end
end

always @( posedge GLB_RESET or posedge TX_CLK155M ) begin
   if ( GLB_RESET==1'b1 )
      TOH_RESERVE_FOR_WR_PAGE[4:0]         <= 5'd0;
   else
      if ( TOH_PAGE_RENEW_ME3==1'b0 && TOH_PAGE_RENEW_ME2==1'b1 )
         TOH_RESERVE_FOR_WR_PAGE[4:0]      <= ROH_RESERVE_FOR_WR_PAGE[4:0];
end


/**** *****/
always @( posedge GLB_RESET or posedge TX_CLK155M ) begin
   if ( GLB_RESET==1'b1 )
      TOH_RD_OHEN                       <= 1'b0;
   else begin
      TOH_RD_OHEN                       <= ((TX_DBIN_FCNT9[3:0]==4'd0 && TX_DBIN_FCNT270[8:0]==9'd6 && TX_DBIN_FCNT8[2:0]==3'b000)) |     // J0 byte enable
                                           ((TX_DBIN_FCNT9[3:0]==4'd1 && TX_DBIN_FCNT270[8:0]==9'd3 && TX_DBIN_FCNT8[2:0]==3'b000)) |     // E1 byte enable
                                           ((TX_DBIN_FCNT9[3:0]==4'd1 && TX_DBIN_FCNT270[8:0]==9'd6 && TX_DBIN_FCNT8[2:0]==3'b000)) |     // F1 byte enable
                                           ((TX_DBIN_FCNT9[3:0]==4'd2 && TX_DBIN_FCNT270[8:0]==9'd0 && TX_DBIN_FCNT8[2:0]==3'b000)) |     // D1 byte enable
                                           ((TX_DBIN_FCNT9[3:0]==4'd2 && TX_DBIN_FCNT270[8:0]==9'd3 && TX_DBIN_FCNT8[2:0]==3'b000)) |     // D2 byte enable
                                           ((TX_DBIN_FCNT9[3:0]==4'd2 && TX_DBIN_FCNT270[8:0]==9'd6 && TX_DBIN_FCNT8[2:0]==3'b000)) |     // D3 byte enable
                                           ((TX_DBIN_FCNT9[3:0]==4'd4 && TX_DBIN_FCNT270[8:0]==9'd3 && TX_DBIN_FCNT8[2:0]==3'b000)) |     // K1 byte enable
                                           ((TX_DBIN_FCNT9[3:0]==4'd4 && TX_DBIN_FCNT270[8:0]==9'd6 && TX_DBIN_FCNT8[2:0]==3'b000)) |     // K2 byte enable
                                           ((TX_DBIN_FCNT9[3:0]==4'd5 && TX_DBIN_FCNT270[8:0]==9'd0 && TX_DBIN_FCNT8[2:0]==3'b000)) |     // D4 byte enable;
                                           ((TX_DBIN_FCNT9[3:0]==4'd5 && TX_DBIN_FCNT270[8:0]==9'd3 && TX_DBIN_FCNT8[2:0]==3'b000)) |     // D5 byte enable;
                                           ((TX_DBIN_FCNT9[3:0]==4'd5 && TX_DBIN_FCNT270[8:0]==9'd6 && TX_DBIN_FCNT8[2:0]==3'b000)) |     // D6 byte enable;
                                           ((TX_DBIN_FCNT9[3:0]==4'd6 && TX_DBIN_FCNT270[8:0]==9'd0 && TX_DBIN_FCNT8[2:0]==3'b000)) |     // D7 byte enable;
                                           ((TX_DBIN_FCNT9[3:0]==4'd6 && TX_DBIN_FCNT270[8:0]==9'd3 && TX_DBIN_FCNT8[2:0]==3'b000)) |     // D8 byte enable;
                                           ((TX_DBIN_FCNT9[3:0]==4'd6 && TX_DBIN_FCNT270[8:0]==9'd6 && TX_DBIN_FCNT8[2:0]==3'b000)) |     // D9 byte enable;
                                           ((TX_DBIN_FCNT9[3:0]==4'd7 && TX_DBIN_FCNT270[8:0]==9'd0 && TX_DBIN_FCNT8[2:0]==3'b000)) |     // D10 byte enable;
                                           ((TX_DBIN_FCNT9[3:0]==4'd7 && TX_DBIN_FCNT270[8:0]==9'd3 && TX_DBIN_FCNT8[2:0]==3'b000)) |     // D11 byte enable;
                                           ((TX_DBIN_FCNT9[3:0]==4'd7 && TX_DBIN_FCNT270[8:0]==9'd6 && TX_DBIN_FCNT8[2:0]==3'b000)) |     // D12 byte enable;
                                           ((TX_DBIN_FCNT9[3:0]==4'd8 && TX_DBIN_FCNT270[8:0]==9'd0 && TX_DBIN_FCNT8[2:0]==3'b000)) |     // S1 byte enable;
                                           ((TX_DBIN_FCNT9[3:0]==4'd8 && TX_DBIN_FCNT270[8:0]==9'd3 && TX_DBIN_FCNT8[2:0]==3'b000)) |     // M1,M0 byte enable;
                                           ((TX_DBIN_FCNT9[3:0]==4'd8 && TX_DBIN_FCNT270[8:0]==9'd6 && TX_DBIN_FCNT8[2:0]==3'b000));      // E2 byte enable;
   end
end

always @( posedge GLB_RESET or posedge TX_CLK155M ) begin
   if ( GLB_RESET==1'b1 )
      TOH_RD_FRAME_END                  <= 1'b0;
   else
      TOH_RD_FRAME_END                  <= (TX_DBIN_FCNT9[3:0]==4'd8 && TX_DBIN_FCNT270[8:0]==9'd269 && TX_DBIN_FCNT8[2:0]==3'b111);
end


always @( posedge GLB_RESET or posedge TX_CLK155M ) begin
   if ( GLB_RESET==1'b1 )
      TOH_RD_PAGE[4:0]                  <= 5'd0;
   else begin
      if ( TOH_RD_FRAME_END==1'b1 )
         TOH_RD_PAGE[4:0]               <= TOH_RD_PAGE[4:0] +5'd1;
      else if ( TOH_RESERVE_FOR_WR_PAGE[4:0]== TOH_RD_PAGE[4:0])       // jump 8 page for read-write page conflict
         TOH_RD_PAGE[4:0]               <= TOH_RD_PAGE[4:0] +5'd16;
   end
end
always @( posedge GLB_RESET or posedge TX_CLK155M ) begin
   if ( GLB_RESET==1'b1 )
      TOH_RD_ADDR[4:0]                  <= 5'd0;
   else begin
      if ( TOH_RD_FRAME_END==1'b1 )
         TOH_RD_ADDR[4:0]               <= 5'd0;
      else if ( TOH_RD_OHEN==1'b1 )
         TOH_RD_ADDR[4:0]               <= TOH_RD_ADDR[4:0] +5'd1;
   end
end

always @( posedge GLB_RESET or posedge TX_CLK155M ) begin
   if ( GLB_RESET==1'b1 ) begin
      TX_TDATA_ME1[63:0]                <= 64'd0;
      TX_TDATA_ME2[63:0]                <= 64'd0;
      TX_TDATA_ME3[63:0]                <= 64'd0;
      TX_FCNT8_ME1[2:0]                 <= 3'd0;
      TX_FCNT8_ME2[2:0]                 <= 3'd0;
      TX_FCNT8_ME3[2:0]                 <= 3'd0;
      TX_FCNT270_ME1[8:0]               <= 9'd0;
      TX_FCNT270_ME2[8:0]               <= 9'd0;
      TX_FCNT270_ME3[8:0]               <= 9'd0;
      TX_FCNT9_ME1[3:0]                 <= 4'd0;
      TX_FCNT9_ME2[3:0]                 <= 4'd0;
      TX_FCNT9_ME3[3:0]                 <= 4'd0;
      TX_MFCNT64_ME1[5:0]               <= 6'd0;
      TX_MFCNT64_ME2[5:0]               <= 6'd0;
      TX_MFCNT64_ME3[5:0]               <= 6'd0;
      TOH_RD_OHEN_ME2                   <= 1'b0;
      TOH_RD_OHEN_ME3                   <= 1'b0;
   end
   else begin
      TX_TDATA_ME1[63:0]                <= TX_DBIN_TDATA[63:0];
      TX_TDATA_ME2[63:0]                <= TX_TDATA_ME1[63:0];
      TX_TDATA_ME3[63:0]                <= TX_TDATA_ME2[63:0];
      TX_FCNT8_ME1[2:0]                 <= TX_DBIN_FCNT8[2:0];
      TX_FCNT8_ME2[2:0]                 <= TX_FCNT8_ME1[2:0];
      TX_FCNT8_ME3[2:0]                 <= TX_FCNT8_ME2[2:0];
      TX_FCNT270_ME1[8:0]               <= TX_DBIN_FCNT270[8:0];
      TX_FCNT270_ME2[8:0]               <= TX_FCNT270_ME1[8:0];
      TX_FCNT270_ME3[8:0]               <= TX_FCNT270_ME2[8:0];
      TX_FCNT9_ME1[3:0]                 <= TX_DBIN_FCNT9[3:0];
      TX_FCNT9_ME2[3:0]                 <= TX_FCNT9_ME1[3:0];
      TX_FCNT9_ME3[3:0]                 <= TX_FCNT9_ME2[3:0];
      TX_MFCNT64_ME1[5:0]               <= TX_DBIN_MFCNT64[5:0];
      TX_MFCNT64_ME2[5:0]               <= TX_MFCNT64_ME1[5:0];
      TX_MFCNT64_ME3[5:0]               <= TX_MFCNT64_ME2[5:0];
      TOH_RD_OHEN_ME2                   <= TOH_RD_OHEN;
      TOH_RD_OHEN_ME3                   <= TOH_RD_OHEN_ME2;
   end
end

always @( posedge GLB_RESET or posedge TX_CLK155M ) begin
   if ( GLB_RESET==1'b1 ) begin
      TX_DBOUT_TDATA[63:0]              <= 64'd0;
      TX_DBOUT_FCNT8[2:0]               <= 3'd0;
      TX_DBOUT_FCNT270[8:0]             <= 9'd0;
      TX_DBOUT_FCNT9[3:0]               <= 4'd0;
      TX_DBOUT_MFCNT64[5:0]             <= 6'd0;
   end
   else begin
      TX_DBOUT_FCNT8[2:0]               <= TX_FCNT8_ME3[2:0];
      TX_DBOUT_FCNT270[8:0]             <= TX_FCNT270_ME3[8:0];
      TX_DBOUT_FCNT9[3:0]               <= TX_FCNT9_ME3[3:0];
      TX_DBOUT_MFCNT64[5:0]             <= TX_MFCNT64_ME3[5:0];
      if ( TOH_RD_OHEN_ME3==1'b1 && TX_SOH_LOOP_EN==1'b1 ) begin
         if ( TX_FCNT9_ME3[3:0]==4'd8 && TX_FCNT270_ME3[8:0]==9'd3 && TX_FCNT8_ME3[2:0]==3'b000 )
            TX_DBOUT_TDATA[63:0]        <= {8'd0, ROH_RAM_DOB[15:0], 40'd0};
         else
            TX_DBOUT_TDATA[63:0]        <= {ROH_RAM_DOB[7:0], 56'd0};
      end
      else begin
         TX_DBOUT_TDATA[63:0]           <= TX_TDATA_ME3[63:0];
      end
   end
end


endmodule 